package main

import (
	"fmt"
	"os"

	log "github.com/Sirupsen/logrus"
	"github.com/urfave/cli"
	"github.com/xianlubird/mydocker/cgroups/subsystems"
	"github.com/xianlubird/mydocker/container"
)

var runCommand = cli.Command{
	Name: "run",
	Usage: `Create a container with namespace and cgroups limit
			mydocker run -ti [command]`,
	Flags: []cli.Flag{
		cli.BoolFlag{
			Name:  "ti",
			Usage: "enable tty",
		},
		cli.StringFlag{
			Name:  "m",
			Usage: "limit memory",
		},
		cli.StringFlag{
			Name:  "cpushare",
			Usage: "cpushare limit",
		},
		cli.StringFlag{
			Name:  "cpuset",
			Usage: "cpuset limit",
		},
		// 配置数据卷
		cli.StringFlag{
			Name:  "v",
			Usage: "volume",
		},
		cli.BoolFlag{
			Name:  "d",
			Usage: "detach container",
		},
		cli.StringFlag{
			Name:  "name",
			Usage: "container name",
		},
	},
	Action: func(context *cli.Context) error {
		// 本函数主要做参数解析 然后传递给Run方法运行
		// 打印context.Args() 此函数返回的第一个参数是除去命令选项的
		var cmdArray []string
		for i, arg := range context.Args() {
			fmt.Printf("arg[%d]: %s\n", i, arg)
			cmdArray = append(cmdArray, arg)
		}
		if len(context.Args()) < 1 {
			return fmt.Errorf("Missing container command")
		}

		// mydocker run -ti /bin/sh
		// 获取ti参数
		tty := context.Bool("ti")

		deatch := context.Bool("d")

		if tty && deatch {
			return fmt.Errorf("ti and d paramter can not both provided")
		}

		// 获取容器名参数
		containerName := context.String("name")

		// 获取数据卷参数
		volume := context.String("v")

		// mydocker run -ti -m xx -cpushare xx -cpuset xx /bash/sh
		// 从命令行参数获取Linux系统资源的限制参数
		println(context.String("m"))
		resConfig := &subsystems.ResourceConfig{
			MemoryLimit: context.String("m"),
			CpuSet:      context.String("cputest"),
			CpuShare:    context.String("cpushare"),
		}

		// Run函数会创建一个容器进程 也就是设置NameSpace等操作
		// 同时会等待容器进程执行完
		Run(tty, cmdArray, resConfig, volume, containerName)
		return nil
	},
}

var initCommand = cli.Command{
	// 子进程（隔离好NameSpace的子进程）会走到这个入口
	Name:  "init",
	Usage: "Init container process run user's process in container. Do not call it outside",
	Action: func(context *cli.Context) error {
		log.Infof("init come on")
		// cmd := context.Args().Get(0) // 也就是 /bin/sh 参数
		// log.Infof("command %s", cmd)

		// // RunContainerInitProcess会重新初始化/proc（proc是代表进程的一个文件系统）初始化好之后呢，如果你不把当前子进程覆盖
		// // 那么你在容器里面ps看到的进程id 1就不是 /bin/sh
		// err := container.RunContainerInitProcess(cmd, nil)
		err := container.RunContainerInitProcess()
		return err
	},
}

var commitCommand = cli.Command{
	Name:  "commit",
	Usage: "commit a container into image",
	Action: func(context *cli.Context) error {
		if len(context.Args()) < 1 {
			return fmt.Errorf("缺少容器名")
		}
		imageName := context.Args().Get(0)
		commitContainer(imageName)
		return nil
	},
}

var listCommand = cli.Command{
	Name:  "ps",
	Usage: "list all containers",
	Action: func(context *cli.Context) error {
		ListContainers()
		return nil
	},
}

var logCommand = cli.Command{
	Name:  "logs",
	Usage: "print logs of a container",
	Action: func(context *cli.Context) error {
		if len(context.Args()) < 1 {
			return fmt.Errorf("Please input your container name")
		}
		containerName := context.Args().Get(0)
		logContainer(containerName)
		return nil
	},
}

var execCommand = cli.Command{
	Name:  "exec",
	Usage: "exec a command into container",
	Action: func(context *cli.Context) error {
		if os.Getenv(ENV_EXEC_PID) != "" { // 如果不等于空，那么表示是子进程
			log.Infof("pid callback pid %d", os.Getgid())
			return nil
		}
		if (len(context.Args())) < 2 {
			return fmt.Errorf("参数缺失")
		}
		containerName := context.Args().Get(0)
		var commandArray []string
		for _, arg := range context.Args().Tail() {
			commandArray = append(commandArray, arg)
		}
		ExecContainer(containerName, commandArray)
		return nil
	},
}

var stopCommand = cli.Command{
	Name:  "stop",
	Usage: "stop a container",
	Action: func(context *cli.Context) error {
		if len(context.Args()) < 1 {
			return fmt.Errorf("Missing container name")
		}
		containerName := context.Args().Get(0)
		stopContainer(containerName)
		return nil
	},
}

var rmCommand = cli.Command{
	Name:  "rm",
	Usage: "remove a stoped container",
	Action: func(context *cli.Context) error {
		if len(context.Args()) < 1 {
			return fmt.Errorf("Missing container name")
		}
		containerName := context.Args().Get(0)
		removeContainer(containerName)
		return nil
	},
}
